#define _PPAL_
#ifdef _PPAL_
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <wait.h>
// Return error libraries
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <exception>

// Own libraries
#include "Config.h"
#include "Logger.h"

#include "ControllerStack.h"
#include "AirStripStack.h"
#include "SharedCounter.h"
#include "Fifo.h"

/* Definition of Global and Static variables */
// Static variables used in the child process.

static char buffer[255];
static char param1[20];

/* Definition of functions */
void createIPCs() {
	Logger::getInstance().createLog();
	Logger::getInstance().setProcessInformation("Launcher:");

	Fifo f_tower_planes("./tmp/fifo_requests");
	f_tower_planes.create_();

	Logger::getInstance().logMessage(Logger::TRACE, "Fifo av-torre creado");

	int amountOfControlers = Config::get_instance().get_int("controllers");

	for(int i = 1; i <= amountOfControlers; ++i){
		std::stringstream name;
		name << "./tmp/Tower_Contr_";
		name << i;
		Fifo f_tower_controlers(name.str());
		f_tower_controlers.create_();
		Logger::getInstance().logMessage(Logger::TRACE, "Fifo torre-ctrl creado");
	}

}

void createProcess(std::string processName, int amountOfProcesses = 1) {
	pid_t pid;

	for (int i = 1; i <= amountOfProcesses; ++i) {
        if ((pid = fork()) < 0) {
            sprintf(buffer, "%s Error: %s", processName.c_str(), strerror(errno));
            Logger::getInstance().logMessage(Logger::ERROR, buffer);
        }
        else if (pid == 0) {
            // Child process. Pass the arguments to the process and call exec
            sprintf(param1, "%d", i);
            sprintf(buffer, "./%s", processName.c_str());
            execlp(buffer, processName.c_str(), param1, (char *) 0);

            sprintf(buffer, "%s Error: %s", processName.c_str(), strerror(errno));
            Logger::getInstance().logMessage(Logger::ERROR, buffer);

            return;
        }
    }
}
/* Main Program */
int main(int argc, char* argv[]) {
	int amountOfControlers = Config::get_instance().get_int("controllers");
	int amountOfAirplanes = Config::get_instance().get_int("airplanes");
	int amountOfAirstrips = Config::get_instance().get_int("airstrips");
	SharedCounter *counter = NULL;
	try {
		createIPCs();
		Semaforo msg_enviados(Semaforo::generarClave("/dev/null",'z'));
		msg_enviados.setVal(0);
		AirStripStack airstrips(AirStripStack::defaul_path, amountOfAirstrips);
		AirStripStack::init(airstrips);
		ControllerStack controllers(ControllerStack::defaul_path, amountOfControlers);
		ControllerStack::init(controllers);
		SharedCounter *counter = new SharedCounter(SharedCounter::default_path, 'a');
		SharedCounter::init(*counter);

		Logger::getInstance().logMessage(Logger::TRACE, "Creo torre de control");
		createProcess("ControlTower");
		Logger::getInstance().logMessage(Logger::TRACE, "Creo Controladores");
		createProcess("Controler",amountOfControlers);
		Logger::getInstance().logMessage(Logger::TRACE, "Creo aviones");
		createProcess("Airplane", amountOfAirplanes);
		for(int i = 0; i < amountOfControlers + amountOfAirplanes + 1; ++i)
			wait(NULL);
		msg_enviados.eliminar();
//		counter->free_();
		counter->deleteMutex();
		delete counter;
	} catch (std::string & m)
	{
		Logger::getInstance().logMessage(Logger::ERROR, m);
//		counter->free_();
		counter->deleteMutex();
		delete counter;
		counter = NULL;
		return -2;
	}
	catch (Exception & e) {
		Logger::getInstance().setProcessInformation("Launcher:");
		//TODO crear una excepcion para tomar el mensaje
		Logger::getInstance().logMessage(Logger::ERROR, "error");
//		counter->free_();
		counter->deleteMutex();
		delete counter;
		counter = NULL;
		return -3;
	}
	catch (std::exception& e) {
		Logger::getInstance().setProcessInformation("Launcher:");
		//TODO crear una excepcion para tomar el mensaje
		Logger::getInstance().logMessage(Logger::ERROR, "error");
//		counter->free_();
		counter->deleteMutex();
		delete counter;
		counter = NULL;
		return -1;
	}
	return 0;
}
#endif
